package org.scboy.coobi.sql.proxy;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.scboy.coobi.sql.Coobi;
import org.scboy.utils.annotations.coobi.EntityParam;
import org.scboy.utils.annotations.coobi.Execute;
import org.scboy.utils.annotations.coobi.Table;
import org.scboy.utils.entitys.coobi.Model;
import org.scboy.utils.entitys.coobi.Page;
import org.scboy.utils.enums.coobi.ExecuteType;

import cn.hutool.core.util.StrUtil;


/**
 * 代理方法实现
 * 
 * @author yanghao
 *
 */
public class MethodProxy implements InvocationHandler {


	private Coobi coobi;
	
	private String tableName;
	
	private Class<?> clazz;
	
	public MethodProxy(Coobi coobi,Class<?> clazz,String tableName) {
		this.coobi=coobi;
		this.clazz=clazz;
		this.tableName=tableName;
	}

	/**
	 * 代理接口方法实现
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		//表名称
		String tableName="";
		//获取查询表
		Table classTable=(Table) clazz.getAnnotation(Table.class);
		if(classTable!=null) {
			tableName=classTable.value();
		}
		// 获取接口方法注解
		Execute exeType = method.getAnnotation(Execute.class);
		//方法重定义Table
		Table methodTable=method.getAnnotation(Table.class);
		if(methodTable!=null) {
			tableName=methodTable.value();
		}
		
		if(StrUtil.isNotEmpty(this.tableName)) {
			tableName=this.tableName;
		}
		// 获取sqlId
		String sqlId = exeType.id();
		// 获取类型
		ExecuteType type = exeType.type();

		// 获取参数名称以及名称
		Parameter[] parameters = method.getParameters();
		// 封装parameNames到Map对象
		Model params = new Model();
		
		if(type != ExecuteType.UPDATE_PARAMS && type!=ExecuteType.AVG  && type!=ExecuteType.MAX  && type!=ExecuteType.MIN  && type!=ExecuteType.SUM ) {
			for (int i = 0; i < parameters.length; i++) {
				//重新封装产生对象
				//判断参数类型
				Object paramObject=args[i];
				EntityParam entityParam=paramObject.getClass().getAnnotation(EntityParam.class);
				
				
				if(paramObject instanceof Model) {
					
					Model _p=(Model)paramObject;
					for (String key : _p.keySet()) {
						params.put(key, _p.get(key));
					}
					
					for (String rc : _p.rcColumns()) {
						params.addRc(rc);
					}
					
					for (String nrc : _p.nrcColumns()) {
						params.addNrc(nrc);
					}
					
				}else if(paramObject instanceof Map || paramObject instanceof HashMap  || paramObject instanceof LinkedHashMap ) {
					Map<?, ?> map=(Map<?, ?>)args[i];
					for (Object key : map.keySet()) {
						params.put((String)key, map.get(key));
					}
				}else if(paramObject instanceof List || paramObject instanceof ArrayList) {
					params.put(parameters[i].getName(), args[i]);
				}else if(entityParam!=null) {
					Field [] fild=paramObject.getClass().getDeclaredFields();
					for (Field field : fild) {
						//field.setAccessible(true);
						params.put(field.getName(), field.get(paramObject));
					}
				} else {
					params.put(parameters[i].getName(), args[i]);
				}
			}
		}

		// 获取方法返回类型
		//Class<?> returnType = method.getReturnType();
		
		if (type == ExecuteType.UPDATE) {
			if(StrUtil.isNotEmpty(sqlId)) {
				return coobi.executeUpdateSqlId(sqlId, params);
			}else {
				return coobi.executeUpdate(tableName, params);
			}
		}else if (type == ExecuteType.UPDATE_PARAMS) {
			return coobi.executeUpdate(tableName, (Model)args[0],(Model)args[1]);
		}else if (type == ExecuteType.DELETE) {
			if(StrUtil.isNotEmpty(sqlId)) {
				return coobi.executeUpdateSqlId(sqlId, params);
			}else {
				return coobi.executeDelete(tableName, params);
			}
		}else if (type == ExecuteType.INSERT) {
			if(StrUtil.isNotEmpty(sqlId)) {
				return coobi.executeUpdateSqlId(sqlId, params);
			}else {
				return coobi.executeInsert(tableName, params);
			}
		}else if (type == ExecuteType.PAGE) {
			Page page=null;
			if(StrUtil.isNotEmpty(sqlId)) {
				page=coobi.executePageSqlId(sqlId, params);
			}else {
				page=coobi.executePage(tableName, params);
			}
			return page;
		} else  if (type == ExecuteType.SELECT){
			List<Model> datas=null;
			if(StrUtil.isNotEmpty(sqlId)) {
				datas=coobi.executeQuerySqlId(sqlId, params);
			}else {
				datas=coobi.executeQuery(tableName, params);
			}
			return datas;
		} else  if (type == ExecuteType.GET){
			Model data=null;
			if(StrUtil.isNotEmpty(sqlId)) {
				data=coobi.executeGetSqlId(sqlId, params);
			}else {
				data=coobi.executeGet(tableName, params);
			}
			return data;
		}else  if (type == ExecuteType.COUNT){
			long  result=0;
			if(StrUtil.isNotEmpty(sqlId)) {
				result=coobi.executeQueryCountSqlId(sqlId, params);
			}else {
				result=coobi.executeQueryCount(tableName, params);
			}
			return result;
		}else if (type == ExecuteType.MAX) {
			return coobi.executeQueryMax(tableName, (String [])args[0],(Model)args[1]);
		}else if (type == ExecuteType.MIN) {
			return coobi.executeQueryMin(tableName, (String [])args[0],(Model)args[1]);
		}else if (type == ExecuteType.SUM) {
			return coobi.executeQuerySum(tableName, (String [])args[0],(Model)args[1]);
		}else if (type == ExecuteType.AVG) {
			return coobi.executeQueryAvg(tableName, (String [])args[0],(Model)args[1]);
		}else {
			throw new Exception("方法没有添加注解org.scboy.coobi.annotation.Execute");
		}
	}
	
}
